#include <iostream>
#include <string>
#include <unistd.h>
#include <sstream>
#include <cassert>
#include <sys/types.h>
#include <sys/wait.h>

#define MAX 100
using namespace std;
// a. 管道的4种情况
///  正常情况下：1.如果管道写端没有数据了，那么读端就必须等待
///             2.管道被写满了，就需要等待读取端读走数据，才能继续写
//              3.如果写端关闭，读端就会一直读取，直到读取到文件末尾.
//              4.如果读端关闭，写入就没有意义，就是异常写入，LINUX会发送信号SIGPIPE(13)，终止目标进程
// b. 管道的5种特性

// 1. 匿名管道，建立一个管道文件，具备亲缘关系的进程可以进行通信
// 2. 匿名管道需要提供同步机制。能读取多少，一般就读取多少。
// 3. 匿名管道是面向字节流的
// 4. 管道也是文件，生命周期随着进程的结束就结束了。就像一直都打开的 ,0,1,2三个默认标准输入输出，进程退出后，会自动释放
// 5. 管道是单向通信的，半双工通信的特殊情况
int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);

    int pipefd[2] = {0};
    assert(!pipe(pipefd)); //为0退出
    cout << pipefd[0] << "  " << pipefd[1] << endl;
    //创建子进程
    pid_t id = fork();
    if (id < 0)
    {
        cerr << "fork" << endl;
    }

    if (id == 0)
    {
        // //父子间通信
        // //child
        // //关闭不需要的管道进行相应的读或者写操作
        close(pipefd[0]);

        for (int i = 0; i < 10; i++)
        {
            sleep(1);
            stringstream msg;
            msg << "Hello parent process,I am child,pid is" << getpid() << " cnt" << i << endl;
            write(pipefd[1], msg.str().c_str(), msg.str().size());
        }
        cout << "--------child write---------------" << endl;
        sleep(5);
        // close(pipefd[1]);
        // exit(0);

        // pid_t id1 = fork();
        // if(id1 >0) exit(0);

        // //孙子进程
        // //我们发现可以通信，切正好验证了对应的ppid是1，就是一个进程成了孤儿进程之后会被领养
        // close(pipefd[0]);

        // for(int i = 0;i<10;i++)
        // {
        //     stringstream msg;
        //     msg<<"Hello parent process,I am grandson,pid is"<<getpid()<<" cnt"<<i<<",myppid is:"<<getppid()<<endl;
        //     write(pipefd[1],msg.str().c_str(),msg.str().size());
        //     sleep(1);
        // }

        close(pipefd[1]);
        exit(0);
    }

    // Parent
    close(pipefd[1]);
    //关闭写端就可以进行读
    // while (1)
    // {
    //     sleep(1);
    //     char msg[MAX] = {0};
    //     int n = read(pipefd[0], msg, sizeof(msg) - 1);
    //     if (n > 0)
    //     {
    //         msg[n] = 0;
    //         cout << getpid() << ", n=" << n << "child say:" << msg << endl;
    //     }
    //     else
    //     {
    //         break;
    //     }
    // }
    sleep(2);
    close(pipefd[0]);
    sleep(2);
    int status = 0;
    pid_t rid = waitpid(id, &status, 0);
    if (rid == id)
    {
        cout << getpid() << ","
             << "wait success,child exit sig:" << (status & 0x7f) << endl;
    }
    return 0;
}